package com.tian.international;

import android.text.TextUtils;

import org.junit.Test;

import java.security.MessageDigest;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * Description:微信支付签名工具（调用微信刷脸sdk时，其中获取调用凭证步骤需要用到参数签名，
 * 详细信息见:<a href="https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=4_3">微信支付签名官方文档</a>）
 * <br/>Author:  tianjinyong
 * <br/>Date:    2019-12-02 15:20
 */
public class WxPaySignUtils {

    /**
     * 在支付过程，生成的nonceString(随机字符串)的字符列表
     */
    private static final String[] RANDOM_STRING_ITEMS = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};

    /**
     * 对微信支付参数进行签名
     *
     * @param signKey    key的设置路径是 微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
     * @param parameters 参数集合
     * @return
     */
    public static String signWxPayParameters(String signKey, SortedMap<String, Object> parameters) {
        //1）生成形如 temp="appid=wxd930ea5d5a258f4f&body=test&device_info=1000&mch_id=10000100&nonce_str=ibuaiVcKdpRxkhJA";这样的字符串
        StringBuffer sb = new StringBuffer();
        Set<String> keySet = parameters.keySet();

        for (String keyName : keySet) {
            String key = keyName;
            Object value = parameters.get(key);
            //如果参数的值为空不参与签名；
            if (value == null)
                continue;

            //填值
            sb.append(key).append("=").append(value.toString()).append("&");
        }

        //2)拼接API密钥,追加signKey
        sb.append("key").append(signKey);

        //3)进行MD5加密
        return stringToMD5(sb.toString(), "utf-8");
    }

    /**
     * 对字符串进行md5加密
     *
     * @param src
     * @param encode
     * @return
     */
    private static String stringToMD5(String src, String encode) {
        String result = null;

        try {
            MessageDigest md = MessageDigest.getInstance("MD5");


            if(encode == null || encode.length() ==0) {
//            if (TextUtils.isEmpty(encode)) {
                result = byteArrayToHexString(md.digest(src.getBytes()));
            } else {
                result = byteArrayToHexString(md.digest(src.getBytes(encode)));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * byte数组转换为16进制字符串
     *
     * @param bytes
     * @return
     */
    private static String byteArrayToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            //去掉高位24位的"0"，因为一个byte转为int后，前24为0
            String hex = Integer.toHexString(0xFF & bytes[i]);
            if (hex.length() == 1) {
                sb.append('0');
            }
            sb.append(hex);
        }
        return sb.toString();
    }

    /**
     * 将map转换为 微信请求需要的"xml"格式
     *
     * @param parameters
     * @return
     */
    public static String mapToXmlString(SortedMap<String, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>\n");
        for (String key : parameters.keySet()) {
            if(key == null || "".equals(key))
//            if (TextUtils.isEmpty(key))
                continue;
            sb.append("<").append(key).append(">").append(parameters.get(key)).append("</").append(key).append(">\n");
        }

        sb.append("</xml>");
        return sb.toString();
    }

    /**
     * 生成随机字符串
     *
     * @param count 随机数位数 至少需要8位
     * @return
     */
    public static String generateNonceStr(int count) throws Exception {

        if (count < 8)
            throw new Exception("count must bigger than 8");

        StringBuffer sb = new StringBuffer();
        int maxIndex = RANDOM_STRING_ITEMS.length - 1;
        int numIndex;

        for (int i = 0; i < count; i++) {
            numIndex = (int) (Math.random() * maxIndex);
            sb.append(RANDOM_STRING_ITEMS[numIndex]);
        }

        return sb.toString();
    }

    @Test
    public static void main(String[] args) {
        String key = "192006250b4c09247ec02edce69f6a2d";
        SortedMap<String, Object> map = new TreeMap<>();
        map.put("appid","wxd930ea5d5a258f4f");
        map.put("mch_id","10000100");
        map.put("device_info","1000");
        map.put("body","test");
        try {
            map.put("nonce_str",generateNonceStr(8));           // 这里为了跟文档的结果对应，直接使用文档的随机数
        } catch (Exception e) {
            e.printStackTrace();
        }
        String sign = signWxPayParameters(key, map);
        map.put("sign",sign);
        String xmlParam = mapToXmlString(map);


        System.out.println(xmlParam);
    }

}
